<?php
/**
 * Created by PhpStorm.
 * User: zd
 * Date: 2018/8/17
 * Time: 17:33
 */

namespace app\api\service;


use app\api\model\Logistics;
use app\api\model\OrderProduct;
use app\api\model\Product;
use app\api\model\Order as OrderModel;
use app\api\model\User;
use app\api\model\UserAddress;
use app\lib\enum\OrderStatusEnum;
use app\lib\exception\OrderException;
use app\lib\exception\ProductException;
use app\lib\exception\UserException;
use think\Db;
use think\Exception;

class Order
{
    /**
     * 订单里面的商品
     * @var
     */
    protected  $orderProducts;

    /**
     * 商品表里面的商品（包含库存量）
     * @var
     */
    protected $products;

    /**
     * 用户id
     * @var
     */
    protected $uid;

    /**
     * 下订单
     * @param $uid
     * @param $orderProducts
     * @return array
     */
    public function place($uid,$w_id,$t_id,$orderProducts){
            $this->orderProducts = $orderProducts;
            $this->products = $this->getProductsByOrder($orderProducts);
            $this->uid = $uid;
            $status = $this->getOrderStatus();
            if (!$status['pass']){
                $status['order_id'] = -1;
                return $status;
            }
            $orderSnap = $this->snapOrder($status);//获取快照
            $order = $this->creatOrder($this->uid,$t_id,$w_id,$orderSnap);//s生成订单
            $order['pass'] = true;
            return $order;
    }
    /**
     * 创建订单
     * @param $uid
     * @param $snap
     * @return array
     * @throws Exception
     */
    private function creatOrder($uid,$t_id,$wu_id,$snap){
        Db::startTrans();
        try{
            $orderSn = $this->makeOrderNo();
            //创建订单，并返回该订单
            $order = \app\api\model\Order::createOrder($orderSn,$uid,$t_id,$wu_id,$snap);
            foreach ($this->orderProducts as &$p){
                $p['order_id'] = $order->id;
            }
            //order-product关系
            $orderProduct = new OrderProduct();
            $orderProduct->saveAll($this->orderProducts);
            Db::commit();
            return [
                'order_sn'=> $orderSn,
                'order_id'=>$order->id,
                'create_time'=>$order->create_time
            ];
        }catch (Exception $exception){
            Db::rollback();
            throw  $exception;
        }

    }
    /**
     * 订单号生成算法
     * @return string
     */
    public static  function makeOrderNo(){
        $yCode = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J');
        $orderSn = $yCode[intval(date('Y')) - 2011] . strtoupper(dechex(date('m'))) . date('d') . substr(time(), -5) . substr(microtime(), 2, 5) . sprintf('%02d', rand(0, 99));
        return $orderSn;
    }
    /**
     * 订单快照
     * @param $status
     * @return array
     */
    private function  snapOrder($status){
        $snap=[
            'orderPrice'=>0,//订单总价
            'totalCount'=>0,//商品总数量
            'pStatusArray'=>[],//订单详情
            'snapAddress'=>'',//购买时地址
            'snapName'=>'',//购买时代表商品名称
            'snapImg'=>'',//购买时代表商品图片
        ];
        $snap['orderPrice'] = $status['orderPrice'];
        $snap['totalCount'] = $status['totalCount'];
        $snap['pStatusArray'] = $status['pStatusArray'];
        $snap['snapAddress'] = json_encode($this->getUserAddress($this->uid));
        $snap['snapName'] = $this->products[0]['name'];
        $snap['snapImg'] = $this->products[0]['main_img_url'];
        if (count($this->products)){
            $snap['snapName'] .= '等';
        }
        return $snap;
    }
    /**
     * 获取用户地址
     * @param $uid
     * @return array|false|\PDOStatement|string|\think\Model
     * @throws UserException
     */
    private function getUserAddress($uid){
        $userAddress = UserAddress::getUserAddressByUID($uid);
        if (null == $userAddress){
            throw new UserException([
                'msg'=>'用户地址不存在，下单失败',
                'err_code'=>60001
            ]);
        }
        return $userAddress;
    }

    /**
     * 根据订单ID，检查订单状态
     * @param $orderID
     * @return array
     */
    public function checkOrderStack($orderID){
        $orderProducts = OrderProduct::getOrderProduct($orderID);
        $this->orderProducts = $orderProducts;
        $this->products = $this->getProductsByOrder($orderProducts);
        $status = $this->getOrderStatus();
        return $status;
    }

    /**
     * 返回订单状态，库存是否够，订单总价，订单详细信息
     * @return array
     */
    private function getOrderStatus(){
        $status=[
            'pass'=>true,//订单状态默认通过
            'orderPrice'=>0, //订单总价
            'totalCount'=>0,//改订单商品总数量
            'pStatusArray'=>[]//订单对应详情信息，历史订单用
        ];
        foreach ($this->orderProducts as $orderProduct){
            $pStatus = $this->getProductStatus($orderProduct['product_id'],$orderProduct['count'], $this->products);
            if (!$pStatus['haveStack']){
                $status['pass'] = false;
            }
            $status['orderPrice'] += $pStatus['totalPrice'];
            $status['totalCount'] +=$orderProduct['count'];
           array_push($status['pStatusArray'],$pStatus);
        }
        return $status;
    }

    /**
     * 获取订单中某个商品在数据库中的真实信息，并计算改商品的总价
     * @param $orderPID
     * @param $orderCount
     * @param $products
     * @return array
     * @throws OrderException
     */
    private function getProductStatus($orderPID,$orderCount,$products){
        $pIndex = -1;//订单中的商品，在根据订单商品id查询出的商品数组的对应下标
        $pStatus=[
            'id'=> 'null',//商品ID
            'haveStack'=>false,//默认没有库存
            'count'=>0,//数量默认为0
            'name'=>'',//商品名称
            'totalPrice'=>0,//订单中每个商品的总价，默认为0。即单价*个数
            'main_img_url'=>'null'//商品图片
        ];
        for ($i = 0;$i<count($products);$i++){
            if ($orderPID == $products[$i]['id']){
                $pIndex = $i;
            }
        }
        if ($pIndex == -1){
            throw  new OrderException([
                'msg'=>'商品id为'.$orderPID. '的商品不存在，创建订单失败'
                ]);
        }else{
            $product = $products[$pIndex];
            $pStatus['id'] = $product['id'];
            $pStatus['name'] = $product['name'];
            $pStatus['count'] = $orderCount;
            $pStatus['totalPrice'] = $orderCount*$product['price'];
            $pStatus['main_img_url'] = $product['main_img_url'];
            if ($product['stock'] >= $orderCount){
                $pStatus['haveStack'] = true;
            }
        }
        return $pStatus;
    }
    /**
     * 根据订单信息查询真实商品信息
     * @param $orderProducts
     * @return false|static[]
     * @throws ProductException
     */
    private function getProductsByOrder($orderProducts){
        $ids = [];
        foreach ($orderProducts as $product){
            array_push($ids,$product['product_id']);
        }
        $products = Product::getProductAllInOrder($ids);
        if (empty($product)){
            throw  new ProductException();
        }
        return $products;
    }

    /**
     * 发送模板消息，并更新订单状态
     * @param $t_id
     * @param $id 订单ID
     * @param $data 快递信息
     * @param string $tplJumpPage
     * @return mixed
     * @throws OrderException
     */
    public function delivery($t_id,$id,$data,$tplJumpPage = ''){
        $order = OrderModel::getOrderInfoByID($id);
        if (!$order){
            throw new OrderException();
        }
        if ($order->status != OrderStatusEnum::PAID){
                throw new OrderException([
                    'code'=>403,
                    'msg'=>'该订单还未支付，或者你已跟新过订单了，请不要再刷新了',
                    'error_code'=>80002
                ]);
        }
        $info=[
          'status'=>  OrderStatusEnum::DELIVERED//订单已发货
        ];
        OrderModel::updateOrderByID($id,$info);//更新订单状态
        Logistics::addLogistics($order->id,$order->user_id,$t_id,$data);//添加快递信息
        $message = new DeliveryMessage($t_id,'订单发货提醒');
        return $message->sendDeliveryMessage($order,$data,$tplJumpPage);
    }

    /**
     * 用户取消订单
     * @param $id
     * @param $uid
     * @return bool
     * @throws OrderException
     */
    public function closeTrade($id,$uid){
        $order = OrderModel::getOrderInfoByID($id);
        $orderList  = OrderModel::getOrderList($uid);
        $list = $orderList->toArray();
        foreach ($list as $v){
            $listID['id'][]= $v['id'];
        }
        if (!$order ||  $orderList->isEmpty() || !in_array($id,$listID['id'])){
            throw new OrderException();
        }
        if ($order->status != OrderStatusEnum::UNPAID){
            throw new OrderException([
                'code'=>403,
                'msg'=>'该订单已经处理过了，不能取消',
                'error_code'=>80003
            ]);
        }
        $info=[
            'status'=>  OrderStatusEnum::CANCEL_TRANSACTION//订单已发货
        ];
        OrderModel::updateOrderByID($id,$info);//更新订单状态
        return true;
    }

    /**
     * 用户确认到货
     * @param $id
     * @param $uid
     * @return bool
     * @throws OrderException
     */
    public function  confirmTrade($id,$uid){
        $order = OrderModel::getOrderInfoByID($id);
        $orderList  = OrderModel::getOrderList($uid);
        $list = $orderList->toArray();
        foreach ($list as $v){
            $listID['id'][]= $v['id'];
        }
        if (!$order ||  $orderList->isEmpty() || !in_array($id,$listID['id'])){
            throw new OrderException();
        }
        if ($order->status != OrderStatusEnum::DELIVERED){
            throw new OrderException([
                'code'=>403,
                'msg'=>'订单还未发货，不能确认到货',
                'error_code'=>80004
            ]);
        }
        $info=[
            'status'=>  OrderStatusEnum::CONFIRM_TRANSACTION//订单已发货
        ];
        OrderModel::updateOrderByID($id,$info);//更新订单状态
        return true;
    }

    /**
     * 获取订单统计
     * @param $t_id
     * @param $num
     * @return false|\PDOStatement|string|\think\Collection
     */
    public function getAllOrders($t_id,$num){
        if ($num == 7){
            $time = time()-7*3600*24;
        }elseif ($num == 15){
            $time = time()-15*3600*24;
        }elseif ($num == 30){
            $time = time()-30*3600*24;
        }
        $result =  OrderModel::getOrderByTime($t_id,$time);
        for ($i=0;$i<$num;$i++){
            $times[] = date('m-d',time()-($num-$i-1)*3600*24);
        }
        $array['info'] = $result;
        $array['time'] = $times;
        return $array;
    }
}